package com.xh.utils;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.xh.common.consts.RConst;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wen
 * @apiNote json序列化工具
 * @since 2022/9/19
 */
@Slf4j
public class JacksonUtil {

    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        // 对于空的对象转json的时候不抛出错误
        OBJECT_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        // 禁用遇到未知属性抛出异常
        OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 序列化BigDecimal时不使用科学计数法输出
        OBJECT_MAPPER.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
        // null的属性不序列化
        OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        OBJECT_MAPPER.setTimeZone(RConst.Time.TIME_ZONE_GMT8);
        OBJECT_MAPPER.registerModule(new JacksonJavaTimeModule());
        // 日期和时间格式化
//        JavaTimeModule javaTimeModule = new JavaTimeModule();
//        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
//        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
//        OBJECT_MAPPER.registerModule(javaTimeModule);
    }

    /**
     * @param obj
     * @return java.lang.String
     * @Name toJson
     * @Description 序列化对象（转json）
     */
    public static String toJson(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof String) {
            return obj.toString();
        }
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.error("json序列化出错：" + obj, e);
            return null;
        }
    }

    /**
     * @param json
     * @param tClass
     * @return T
     * @Name parse
     * @Description 反序列化（json转为Bean）
     */
    public static <T> T parse(String json, Class<T> tClass) {
        if (StrUtil.isEmpty(json)) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(json, tClass);
        } catch (IOException e) {
            log.error("json解析出错：" + json, e);
            return null;
        }
    }

    /**
     * @param json
     * @param eClass
     * @return java.util.List<E>
     * @Name parseList
     * @Description 反序列化（json转List）
     */
    public static <E> List<E> parseList(String json, Class<E> eClass) {
        return nativeRead(json, List.class, eClass);
    }

    /**
     * @param json
     * @param kClass
     * @param vClass
     * @return java.util.Map<K, V>
     * @Name parseMap
     * @Description 反序列化（json转Map）
     */
    public static <K, V> Map<K, V> parseMap(String json, Class<K> kClass, Class<V> vClass) {
        return nativeRead(json, Map.class, kClass, vClass);
    }

    /**
     * @param json
     * @param kClass
     * @param vClass
     * @return java.util.LinkedHashMap<K, V>
     * @Name parseLinkedHashMap
     * @Description 反序列化（json转LinkedHashMap）
     */
    public static <K, V> LinkedHashMap<K, V> parseLinkedHashMap(String json, Class<K> kClass, Class<V> vClass) {
        return nativeRead(json, LinkedHashMap.class, kClass, vClass);
    }

    /**
     * @param json
     * @param type
     * @return T
     * @Name nativeRead
     * @Description json转复杂对象
     */
    public static <T> T nativeRead(String json, TypeReference<T> type) {
        if (StrUtil.isEmpty(json)) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(json, type);
        } catch (IOException e) {
            log.error("json解析出错：" + json, e);
            return null;
        }
    }

    /**
     * @param json         json字符串
     * @param javaClazz    需要转换的java对象类型，
     *                     例如：List.class, ArrayList.class, Map.class, HashMap.class, LinkedHashMap.class
     * @param genericClazz 泛型类型
     * @return T
     * @name nativeRead
     * @description json转对象
     * @author wen
     * @date 2021/1/20
     */
    public static <T> T nativeRead(String json, Class<?> javaClazz, Class<?>... genericClazz) {
        if (StrUtil.isEmpty(json)) {
            return null;
        }
        try {
            JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(javaClazz, genericClazz);
            return OBJECT_MAPPER.readValue(json, javaType);
        } catch (Exception e) {
            log.error("json解析出错", e);
            return null;
        }
    }

    /**
     * 序列化
     */
    @Deprecated
    public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException {
            if (value != null) {
                String timestamp = String.valueOf(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
                gen.writeNumber(timestamp);
            }
        }
    }

    /**
     * 反序列化
     */
    @Deprecated
    public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext)
                throws IOException {
            long timestamp = p.getValueAsLong();
            if (timestamp > 0) {
                return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
            } else {
                return null;
            }
        }
    }

    /**
     * @author wen
     * @apiNote 时间模型处理
     * @since 2022/12/30
     */
    public static class JacksonJavaTimeModule extends SimpleModule {

        private static final String PATTERN_DATE = "yyyy-MM-dd";
        private static final String PATTERN_TIME = "HH:mm:ss";

        /**
         * java 8 时间格式化
         */
        public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(PATTERN_DATE);
        public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(PATTERN_TIME);

        public JacksonJavaTimeModule() {
            super(PackageVersion.VERSION);
            this.addDeserializer(LocalDateTime.class, new JacksonJavaTimeModule.LocalDateTimeDeserializer());
            this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DATE_FORMATTER));
            this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(TIME_FORMATTER));
            this.addDeserializer(Date.class, new JacksonJavaTimeModule.DateDeserializer());

            this.addSerializer(LocalDateTime.class, new JacksonJavaTimeModule.LocalDateTimeSerializer());
            this.addSerializer(LocalDate.class, new LocalDateSerializer(DATE_FORMATTER));
            this.addSerializer(LocalTime.class, new LocalTimeSerializer(TIME_FORMATTER));
            this.addSerializer(Date.class, new JacksonJavaTimeModule.DateSerializer());

            // Jackson全局转化long类型为String，解决jackson序列化时传入前端Long类型缺失精度问题
            this.addSerializer(Long.class, new ToStringSerializer());
        }

        /**
         * description:序列化
         * LocalDateTime序列化为毫秒级时间戳
         */
        public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
            @Override
            public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers)
                    throws IOException {
                if (value != null) {
                    long timestamp = DateUtil.localDateTimeToMills(value);
                    gen.writeNumber(timestamp);
                }
            }
        }

        /**
         * description:反序列化
         * 毫秒级时间戳序列化为LocalDateTime
         */
        public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
            @Override
            public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext)
                    throws IOException {
                long timestamp = p.getValueAsLong();
                if (timestamp > 0) {
                    return DateUtil.millsToLocalDateTime(timestamp);
                } else {
                    return null;
                }
            }
        }

        /**
         * 序列化
         */
        public static class DateSerializer extends JsonSerializer<Date> {
            @Override
            public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                if (value != null) {
                    gen.writeNumber(value.getTime());
                }
            }
        }

        /**
         * 反序列化
         */
        public static class DateDeserializer extends JsonDeserializer<Date> {
            @Override
            public Date deserialize(JsonParser p, DeserializationContext deserializationContext) throws IOException {
                long timestamp = p.getValueAsLong();
                return timestamp > 0 ? new Date(timestamp) : null;
            }
        }

    }


}
